package com.nineclock.sign.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nineclock.common.entity.PageResult;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.filter.CurrentUserHolder;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.common.utils.DateTimeUtil;
import com.nineclock.sign.dto.*;
import com.nineclock.sign.excel.CustomHandler;
import com.nineclock.sign.mapper.SignPictureMapper;
import com.nineclock.sign.mapper.SysUserMapper;
import com.nineclock.sign.pojo.SignInfo;
import com.nineclock.sign.pojo.SignPicture;
import com.nineclock.sign.service.SignInfoService;
import com.nineclock.sign.mapper.SignInfoMapper;
import com.nineclock.system.dto.DepartmentOrUserSimpleDTO;
import com.nineclock.system.dto.SysCompanyUserDTO;
import com.nineclock.system.feign.SysCompanyUserFeign;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 */
@Service
@Transactional
@Slf4j
public class SignInfoServiceImpl implements SignInfoService{

    @Autowired(required = false)
    private SignInfoMapper signInfoMapper;

    @Autowired
    private SysCompanyUserFeign sysCompanyUserFeign;


    @Autowired
    private SysUserMapper userMapper;

    @Autowired
    private SignPictureMapper signPictureMapper;


    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public PageResult<SignPageDTO> querySignPage(String startTime, String endTime, Integer page, Integer pageSize) {

        //参数校验

        // 1.获取起止日期内(包含起止日期)，所有日期的集合
        List<String> spanDateList = DateTimeUtil.getSpanDateList(startTime, endTime);

        //获取当前企业下所有的员工数据分页列表
        PageResult<SysCompanyUserDTO> pageResult = sysCompanyUserFeign.queryAllCompanyUserByPage(page, pageSize).getData();
        List<SysCompanyUserDTO> companyUserDTOList = pageResult.getRows();

        //查询每个员工每天的签到情况
        List<SignPageDTO> signInfoList = this.getSignList(startTime, endTime, spanDateList, companyUserDTOList);

        PageResult<SignPageDTO> SignPageDTOPageResult = new PageResult<>(pageResult.getTotal(), pageResult.getTotalPage(), signInfoList);
        return SignPageDTOPageResult;
    }

    @Override
    public void exportSignList(String startTime, String endTime) throws IOException {
        //获取该企业的所有员工信息
        List<String> spanDateList = DateTimeUtil.getSpanDateList(startTime, endTime);
        List<SysCompanyUserDTO> companyUserDTOList = sysCompanyUserFeign.queryAllCompanyUser().getData();

        //查询所有员工的签到数据
        List<SignPageDTO> signList = this.getSignList(startTime, endTime, spanDateList, companyUserDTOList);


        //生成excel并输出到response
        //获取response
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletResponse response = servletRequestAttributes.getResponse();
        response.setHeader("Content-disposition", "attachment;filename=Attendance.xls");
        response.setContentType("application/octet-stream;charset=UTF-8");
        response.setCharacterEncoding("utf-8");

        // 3.通过response获取输出流, 并生成的Excel输出
        EasyExcel.write(response.getOutputStream())
                .excelType(ExcelTypeEnum.XLS)
                .head(this.handleHeaders(signList))
                .registerWriteHandler(this.horizontalCellStyleStrategy())
                .registerWriteHandler(new CustomHandler())
                .sheet("签到记录")
                .doWrite(this.handleData(signList));
    }

    @Override
    public String generateSignReport(Long companyId) {
        // 1.获取当月的第一天、最后一天
        String startTime = DateTimeUtil.getCurrentMonthFirstDay();
        String endTime = DateTimeUtil.getCurrentMonthLastDay();

        // 获取起止日期内(包含起止日期)，所有日期的集合
        List<String> spanDateList = DateTimeUtil.getSpanDateList(startTime, endTime);

        // 2.获取企业的员工列表
        List<SysCompanyUserDTO> companyUserDTOS = sysCompanyUserFeign.queryAllUserByCompanyId(companyId).getData();

        // 3.调用公共方法，获取签到数据
        List<SignPageDTO> signPageDTOS = this.getSignList(startTime, endTime, spanDateList, companyUserDTOS);

        // 4.生成Excel报表
        // 4.1 创建报表放置的服务端文件夹
        String foldername = "E:" + File.separator + "签到数据" + File.separator + companyId;
        File folder = new File(foldername);

        // 4.2 如果文件夹不存在，创建文件夹
        if(!folder.exists()){
            folder.mkdirs();
        }

        // 4.3 指定文件名，D:\考勤数据\xxx公司-2021-11-考勤数据.xls
        String filename = foldername + File.separator + companyUserDTOS.get(0).getCompanyName() + "-" + startTime.substring(0, 7) + "-考勤数据.xls";

        // 4.4 写文件
        EasyExcel.write(new File(filename))
                .excelType(ExcelTypeEnum.XLS)
                .head(this.handleHeaders(signPageDTOS))
                .registerWriteHandler(this.horizontalCellStyleStrategy())
                .registerWriteHandler(new CustomHandler())
                .sheet("签到报表")
                .doWrite(this.handleData(signPageDTOS));


        return filename;
    }

    private List<SignPageDTO> getSignList(String startTime, String endTime, List<String> spanDateList, List<SysCompanyUserDTO> companyUserDTOList) {
        List<SignPageDTO> signPageDTOList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(companyUserDTOList)){
            // 遍历企业员工列表
            for (SysCompanyUserDTO sysCompanyUserDTO : companyUserDTOList) {
                SignPageDTO signPageDTO = new SignPageDTO();

                //封装数据到dto
                DepartmentOrUserSimpleDTO departmentSimpleDTO = new DepartmentOrUserSimpleDTO();
                departmentSimpleDTO.setId(sysCompanyUserDTO.getDepartmentId());
                departmentSimpleDTO.setName(sysCompanyUserDTO.getDepartmentName());
                signPageDTO.setDepartment(departmentSimpleDTO);

                signPageDTO.setUsername(sysCompanyUserDTO.getUserName());
                signPageDTO.setWorkNumber(sysCompanyUserDTO.getWorkNumber());
                signPageDTO.setPost(sysCompanyUserDTO.getPost());

                //查询该员工的签到数据
                List<SignsDTO> signsInDb = signInfoMapper.countByDate(startTime,endTime,sysCompanyUserDTO.getId());

                List<SignsDTO> signs = new ArrayList<>();
                for (String everyDay : spanDateList) {
                    SignsDTO signsDTO = new SignsDTO();
                    signsDTO.setSignDate(everyDay);
                    signsDTO.setSignCount(0);
                    for (SignsDTO sign : signsInDb) {
                        if (signsDTO.getSignDate().equals(sign.getSignDate())){
                            signsDTO.setSignCount(sign.getSignCount());
                        }
                    }
                    signs.add(signsDTO);
                }
                signPageDTO.setSigns(signs);

                signPageDTOList.add(signPageDTO);
            }
        }
        return signPageDTOList;
    }

    /**
     * 处理每行数据
     * @param signList
     * @return
     */
    private List<List<String>> handleData(List<SignPageDTO> signList) {
        List<List<String>> rowdatas = new ArrayList<>();

        if (!CollectionUtils.isEmpty(signList)) {
            for (SignPageDTO sign : signList) {
                // 每一行基本信息
                List<String> rowData = new ArrayList<>();
                rowData.add(sign.getUsername());
                rowData.add(sign.getWorkNumber());
                rowData.add(sign.getDepartment().getName());
                rowData.add(sign.getPost());
                List<SignsDTO> signs = sign.getSigns();
                if (!CollectionUtils.isEmpty(signs)){
                    for (SignsDTO signsDTO : signs) {
                        rowData.add(String.valueOf(signsDTO.getSignCount()));
                    }
                }
                rowdatas.add(rowData);
            }
        }
        return rowdatas;
    }

    /**
     * 设置样式
     */
    public HorizontalCellStyleStrategy horizontalCellStyleStrategy() {

        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        //内容策略 - 水平居中
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);

        //设置字体
        WriteFont font = new WriteFont();
        font.setFontName("阿里巴巴普惠体");
        font.setFontHeightInPoints((short) 11);
        contentWriteCellStyle.setWriteFont(font);
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(contentWriteCellStyle, contentWriteCellStyle);

        return horizontalCellStyleStrategy;
    }

    /**
     * 处理表头
     * @param signPageDTOList
     * @return
     */
    private List<List<String>> handleHeaders(List<SignPageDTO> signPageDTOList) {
        List<List<String>> headers = new ArrayList<>();

        headers.add(Arrays.asList("姓名"));
        headers.add(Arrays.asList("工号"));
        headers.add(Arrays.asList("部门"));
        headers.add(Arrays.asList("职位"));

        if (!CollectionUtils.isEmpty(signPageDTOList)){
            //取任意一条的日期数据作为表头就行
            List<SignsDTO> signs = signPageDTOList.get(0).getSigns();
            if (!CollectionUtils.isEmpty(signs)){
                for (SignsDTO sign : signs) {
                    headers.add(Arrays.asList(sign.getSignDate()));
                }
            }
        }

        return headers;
    }


    @Override
    public void insert(Map map) {
        //校验参数
        if(CollectionUtils.isEmpty(map)){
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }

        //获取数据
        Date now = new Date();
        String dateToStr = DateTimeUtil.dateToStr(now);
        String createDate = dateToStr.substring(0, 10);
        String createMonth = dateToStr.substring(0, 7);

        String latstr = (String) map.get("lat");
        String lngstr = (String) map.get("lng");
        double lat = Double.parseDouble(latstr);
        double lng = Double.parseDouble(lngstr);
        BigDecimal bigDecimal = new BigDecimal(lat);
        BigDecimal bigDecimal1 = new BigDecimal(lng);


//        new BigDecimal(34.1558040000)
//        new BigDecimal(108.8937340000)


        //保存数据
        SignInfo entity=new SignInfo();
        entity.setCompanyId(CurrentUserHolder.get().getCompanyId());
        entity.setCompanyUserId(CurrentUserHolder.get().getCompanyUserId());
        entity.setCreateTime(now);
        entity.setCreateDate(createDate);
        entity.setCreateMonth(createMonth);
        entity.setLat(bigDecimal);
        entity.setLng(bigDecimal1);
        entity.setAddress((String) map.get("address"));
        entity.setRemark((String) map.get("remark"));
        entity.setVisit((String) map.get("visit"));
        entity.setImei((String) map.get("imei"));
        signInfoMapper.insert(entity);

        //将数据存到redis缓存中
//        redisTemplate.opsForValue().set(entity.getCompanyId()+""+entity.getCompanyUserId()+""+entity.getCreateDate(),entity);

        log.info(entity.getId().toString());


        //保存图片
        String regex = ",";
        String[] images = map.get("images").toString().split(regex);
//        LambdaQueryWrapper<SignInfo> wrapper=new LambdaQueryWrapper<>();
//        wrapper.eq(SignInfo::getCompanyId,CurrentUserHolder.get().getCompanyId());
//        wrapper.eq(SignInfo::getCompanyUserId,CurrentUserHolder.get().getCompanyUserId());
//        wrapper.eq(SignInfo::getCreateTime,entity.getCreateTime());
//        SignInfo signInfo = signInfoMapper.selectOne(wrapper);
        for (String image : images) {
            SignPicture pictuteEntity=new SignPicture();
            pictuteEntity.setSignId(entity.getId());
            pictuteEntity.setUrl("https://nineclock-heima.oss-cn-beijing.aliyuncs.com/"+image);
            signPictureMapper.insert(pictuteEntity);
        }
    }

    /**
     * APP: 获取当前用户当天签到次数
     * @return
     */
    @Override
    public Integer getDayCount() {

        Date now = new Date();
        String dateToStr = DateTimeUtil.dateToStr(now);
        String createDate = dateToStr.substring(0, 10);
        //使用redis缓存
//        List list = (List) redisTemplate.opsForValue()
//                .get(CurrentUserHolder.get().getCompanyId() + ""
//                        + CurrentUserHolder.get().getCompanyUserId()+""+createDate);

        LambdaQueryWrapper<SignInfo> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(SignInfo::getCompanyId,CurrentUserHolder.get().getCompanyId());
        wrapper.eq(SignInfo::getCompanyUserId,CurrentUserHolder.get().getCompanyUserId());
        wrapper.eq(SignInfo::getCreateDate,createDate);
        List<SignInfo> signInfos = signInfoMapper.selectList(wrapper);

        return signInfos.size();


    }

    /**
     * APP: 获取团队员工打卡列表
     * @param dateStr
     * @return
     */
    @Override
    public List<SignDTO> listSignAllUser(String dateStr) {

        List<SignDTO> signDTOList = new ArrayList<>();

        if(StringUtils.isEmpty(dateStr)){
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }

        //根据企业id查询所有员工
        List<SysCompanyUserDTO> companyUserDTOList = sysCompanyUserFeign.queryAllUserByCompanyId(CurrentUserHolder.get().getCompanyId()).getData();

        //遍历获取所有员工的名字和员工id
        if(!CollectionUtils.isEmpty(companyUserDTOList)){
            for (SysCompanyUserDTO sysCompanyUserDTO : companyUserDTOList) {
                //根据员工id,企业id，时间查询签到次数
                LambdaQueryWrapper<SignInfo> wrapper=new LambdaQueryWrapper<>();
                wrapper.eq(SignInfo::getCompanyId,CurrentUserHolder.get().getCompanyId());
                wrapper.eq(SignInfo::getCompanyUserId,sysCompanyUserDTO.getId());
                wrapper.eq(SignInfo::getCreateDate,dateStr);
                List<SignInfo> signInfoList = signInfoMapper.selectList(wrapper);
                if(!CollectionUtils.isEmpty(signInfoList)){
                    List<SignInfoDTO> signInfoDTOList = signInfoList.stream().map(signInfo -> {
                        SignInfoDTO signInfoDTO = BeanHelper.copyProperties(signInfo, SignInfoDTO.class);
                        signInfoDTO.setDayCount(getDayCount1(dateStr,signInfo.getCompanyUserId(),signInfo.getCompanyId()).toString());
                        signInfoDTO.setMonthCount(getMonthCount(signInfo.getCompanyUserId(),signInfo.getCreateMonth()).toString());
                        LambdaQueryWrapper<SignPicture> wrapper1=new LambdaQueryWrapper<>();
                        wrapper1.eq(SignPicture::getSignId,signInfo.getId());
                        List<SignPicture> signPictureList = signPictureMapper.selectList(wrapper1);

                        String images="";
                        for (SignPicture signPicture : signPictureList) {
                            String url = signPicture.getUrl();
                            images = String.join(",", url);
                        }
                        signInfoDTO.setImages(images);
                        String[] split = images.split(",");
                        signInfoDTO.setSignPictureUrlList(split);
                        return signInfoDTO;
                    }).collect(Collectors.toList());
                    SignDTO signDTO = new SignDTO();
                    signDTO.setSignResponseList(signInfoDTOList);
                    signDTO.setUsername(sysCompanyUserDTO.getUserName());
                    signDTOList.add(signDTO);
                }
            }
        }
        return signDTOList;
    }

    /**
     * APP: 查询本月签到记录
     * @param dateStr
     * @return
     */
    @Override
    public List<SignInfoDTO> pagingSignCurrentUserByMonth(String dateStr) {
        //校验参数
        if(StringUtils.isEmpty(dateStr)){
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }

        LambdaQueryWrapper<SignInfo> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(SignInfo::getCompanyId,CurrentUserHolder.get().getCompanyId());
        wrapper.eq(SignInfo::getCompanyUserId,CurrentUserHolder.get().getCompanyUserId());
        wrapper.eq(SignInfo::getCreateMonth,dateStr);
        List<SignInfo> signInfoList = signInfoMapper.selectList(wrapper);
        if(!CollectionUtils.isEmpty(signInfoList)){
            List<SignInfoDTO> signInfoDTOList = signInfoList.stream().map(signInfo -> {
                SignInfoDTO signInfoDTO = BeanHelper.copyProperties(signInfo, SignInfoDTO.class);
                signInfoDTO.setDayCount(getDayCount1(signInfo.getCreateDate(), signInfo.getCompanyUserId(), signInfo.getCompanyId()).toString());
                signInfoDTO.setMonthCount(getMonthCount(signInfo.getCompanyUserId(), signInfo.getCreateMonth()).toString());
                LambdaQueryWrapper<SignPicture> wrapper1 = new LambdaQueryWrapper<>();
                wrapper1.eq(SignPicture::getSignId, signInfo.getId());
                List<SignPicture> signPictureList = signPictureMapper.selectList(wrapper1);

                String images = "";
                for (SignPicture signPicture : signPictureList) {
                    String url = signPicture.getUrl();
                    images = String.join(",", url);
                }
                signInfoDTO.setImages(images);
                String[] split = images.split(",");
                signInfoDTO.setSignPictureUrlList(split);
                return signInfoDTO;
            }).collect(Collectors.toList());
            return signInfoDTOList;
        }
        return null;
    }

    private Integer getDayCount1(String dateStr, Long companyUserId, Long companyId) {
        LambdaQueryWrapper<SignInfo> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(SignInfo::getCompanyId,companyId);
        wrapper.eq(SignInfo::getCompanyUserId,companyUserId);
        wrapper.eq(SignInfo::getCreateDate,dateStr);
        Integer count = signInfoMapper.selectCount(wrapper);
        return count;
    }

    private Integer getMonthCount(Long companyUserId,String createMonth) {

        LambdaQueryWrapper<SignInfo> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(SignInfo::getCompanyId,CurrentUserHolder.get().getCompanyId());
        wrapper.eq(SignInfo::getCompanyUserId,companyUserId);
        wrapper.eq(SignInfo::getCreateDate,createMonth);
        Integer count = signInfoMapper.selectCount(wrapper);

        return count;
    }
}




